/* weehttpd
* Copyright (c) 2008 Jeffery Myers
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#ifndef _WeeHTTPDCONNECTION_H_
#define _WeeHTTPDCONNECTION_H_

#include "httpd.h"

inline int generateSessionID(void)
{
	short s[2];
	s[0] = rand();
	s[1] = rand();

	return *((int*)s);
}

class HTTPConnection
{
public:
	HTTPConnection( WeeHTTPDOptions &op = WeeHTTPDOptions()) : connectionID(0),
		requestComplete(false),
		headerComplete(false),
		contentSize(0),
		bodyEnd(0),
		request(eUnknown),
		sessionID(0) ,
		options(op){};

	HTTPConnection( const HTTPConnection &c) : connectionID(c.connectionID),
		requestComplete(c.requestComplete),
		headerComplete(c.headerComplete),
		contentSize(c.contentSize),
		bodyEnd(c.bodyEnd),
		request(c.request),
		sessionID(c.sessionID) ,
		options(c.options)
	{
		processingTasks = c.processingTasks; 
		pendingTasks = c.pendingTasks;
	}

	HTTPConnection& operator =( const HTTPConnection &c)
	{
		connectionID = c.connectionID;
		requestComplete = c.requestComplete;
		headerComplete = c.headerComplete;
		contentSize = c.contentSize;
		bodyEnd = c.bodyEnd;
		request = c.request;
		sessionID = c.sessionID;
		options = c.options;
		processingTasks = c.processingTasks; 
		pendingTasks = c.pendingTasks;
		return *this;
	}


	void flush(void)
	{
		body = "";
		contentSize = 0;
		bodyEnd = 0;
		headerComplete = false;
		requestComplete = false;
		request = eUnknown;
		vdir = "";
		resource = "";
		host = "";
		header.clear();
	}

	bool update(void);

	unsigned int connectionID;

	// the current request as we process it
	std::string currentData;
	std::string body;
	size_t      contentSize;
	size_t      bodyEnd;
	bool		headerComplete;
	bool		requestComplete;

	int sessionID;

	WeeHTTPDOptions   &options;

	WeeHTTPRequestType request;
	std::string	    vdir;
	std::string	    resource;
	std::string	    host;
	std::map<std::string, std::string> header;

	void fillRequest(WeeHTTPRequest &req);

	class HTTPTask
	{
	public:
		HTTPTask(WeeHTTPReply& r, WeeHTTPDOptions &o, bool noBody);
		HTTPTask(const HTTPTask& t);

		HTTPTask& operator = (const HTTPTask& t );
		virtual ~HTTPTask (void){};

		void generateBody (WeeHTTPReply& r, bool noBody);

		bool update(unsigned int connectionID);

		// std::string page;
		size_t pos;
		WeeHTTPDOptions &options;

		// a binary data management class
		class PageBuffer
		{
		public:
			virtual ~PageBuffer(){if(data)free(data);}
			PageBuffer() : bufferSize(0), data(NULL){};

			PageBuffer( const char* str )
			{
				bufferSize = strlen(str);
				data = (char*)malloc(bufferSize);
				memcpy(data,str,bufferSize);
			}

			PageBuffer( const std::string &r )
			{
				bufferSize = r.size();
				data = (char*)malloc(bufferSize);
				memcpy(data,r.c_str(),bufferSize);
			}

			PageBuffer( const PageBuffer &r )
			{
				bufferSize = r.size();
				data = (char*)malloc(bufferSize);
				memcpy(data,r.data,bufferSize);
			}

			size_t append ( const char * newData, size_t newSize )
			{
				if (!data)
				{
					data = (char*)malloc(newSize);
					memcpy(data,newData,newSize);
					bufferSize = newSize;
				}
				else
				{
					char *p = (char*)malloc(bufferSize+newSize);
					memcpy(p,data,bufferSize);
					memcpy(p+bufferSize,newData,newSize);
					bufferSize+=newSize;
					free(data);
					data = p;
				}
				return bufferSize;
			}

			PageBuffer& operator += ( const char* p )
			{
				if (p)
					append(p,strlen(p));
				return *this;
			}

			PageBuffer& operator += ( const std::string &p )
			{
				if (p.size())
					append(p.c_str(),p.size());
				return *this;
			}

			PageBuffer& operator = ( const char* p )
			{
				if (data)
					free (data);
				data = NULL;

				if (p)
					append(p,strlen(p));
				return *this;
			}

			PageBuffer& operator = ( const std::string &p )
			{
				if (data)
					free (data);
				data = NULL;

				if (p.size())
					append(p.c_str(),p.size());
				return *this;
			}

			PageBuffer& operator = ( const PageBuffer &p )
			{
				if (data)
					free (data);
				data = NULL;

				if (p.size())
					append(p.getData(),p.size());
				return *this;
			}
			const size_t size(void)const {return bufferSize;}
			const char* getData ( void ) const { return data;}

		protected:
			size_t bufferSize;
			char * data;
		};
		PageBuffer pageBuffer;

		bool forceClose;
	};

	class PendingHTTPTask : public HTTPTask
	{
	public:
		PendingHTTPTask(WeeHTTPReply& r, WeeHTTPRequest &rq, WeeHTTPVDir *d, WeeHTTPDOptions &o,  bool noBody): HTTPTask(r,o,noBody), request(rq), reply(r), dir(d){};
		WeeHTTPRequest request;
		WeeHTTPReply reply;
		WeeHTTPVDir *dir;
	};

	std::vector<HTTPTask> processingTasks;  // tasks working
	std::vector<PendingHTTPTask> pendingTasks;	  // tasks waiting
};

typedef std::map<int,HTTPConnection> HTTPConnectionMap;



#endif //_WeeHTTPDCONNECTION_H_


// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
